<template>
  <q-field ref="selectTree" v-model="selected" :class="fieldCls" :disable="disable" :error="!isValid"
           :error-message="placeholder" :readonly="readonly" class="q-field__text" lazy-rules="ondemand"
           v-bind="$attrs">
    <template v-for="item in Object.keys(useSlots())" v-slot:[item]>
      <slot :name="item"></slot>
    </template>
    <template v-slot:control>
      <span v-if="!showText" class="placeholder">{{ placeholder }}</span>
      <QxTooltip v-else>{{ showText }}</QxTooltip>
    </template>
    <template v-slot:append>
      <q-icon v-if="showClearIcon" class="field-clear-icon cursor-pointer" name="cancel"
              @click.stop="handleClear"></q-icon>
      <q-icon :class="showPopup ? 'rotate-180' : ''" class="q-select__dropdown-icon" name="arrow_drop_down"></q-icon>
    </template>
    <q-popup-proxy v-model="showPopup" :no-parent-event="readonly || disable" :offset="[0, 5]" anchor="bottom left"
                   breakpoint="0" class="q-pa-xs" fit no-focus no-refocus self="top left" transition-hide="jump-up"
                   transition-show="jump-down" @hide="popupBlur">
      <qx-tree ref="treeRef" v-model="selected" classes="no-shadow bg-white" maxHeight="50vh" v-bind="treeBind"
               @change="updateModelValue"></qx-tree>
    </q-popup-proxy>
  </q-field>
</template>

<script setup>
import QxTree from 'components/Global/QxTree.vue'
import QxTooltip from 'components/Global/Tools/QxTooltip.vue'
import { isEmpty } from 'src/utils/utils'
import { computed, nextTick, onBeforeUnmount, onMounted, ref, toRef, useSlots, watch } from 'vue'

const prop = defineProps({
  type: String,
  props: Object,
  field: String,
  dicUrl: String,
  options: Array,
  rowInfo: Object,
  change: Function,
  disable: Boolean,
  addName: Boolean,
  dicQuery: Object,
  multiple: Boolean,
  readonly: Boolean,
  dicMethods: String,
  placeholder: String,
  lazyRules: [Boolean, String],
  clearable: { type: Boolean, default: true },
  modelValue: [String, Object, Number, Array]
})

const emits = defineEmits(['change', 'update:modelValue'])

const showText = ref('')
const treeRef = ref(null)
const isValid = ref(true)
const selected = ref(void 0)
const selectTree = ref(null)
const showPopup = ref(false)

const showClearIcon = computed(() => {
  const { clearable, disable, readonly } = prop
  if (readonly || disable || !clearable) return false
  return !!selected.value
})
const label = computed(() => prop.props?.label || 'label')
const fieldCls = computed(() => showPopup.value ? 'q-field--focused q-field--highlighted' : '')
const treeBind = computed(() => {
  // eslint-disable-next-line no-unused-vars
  const { change, placeholder, modelValue, type, ...bind } = prop
  bind.noSelectionUnset = true
  return bind
})

const formInfo = toRef(prop, 'rowInfo')
const formatFormInfo = () => {
  if (prop.addName && formInfo.value) formInfo.value[`SSS_${prop.field}`] = showText.value
}
const updateModelValue = (target, node) => {
  if (isEmpty(node)) showText.value = ''
  else {
    if (prop.multiple) showText.value = node.map(el => el[label.value]).join(', ')
    else showText.value = node[label.value]
  }
  if (!prop.multiple) showPopup.value = false
  if (prop.change) prop.change(target, node)
  else emits('change', target, node)
}
const initData = () => {
  if (selected.value === prop.modelValue) return formatFormInfo()
  if (isEmpty(prop.modelValue)) return (selected.value = void 0)
  if (!showPopup.value) showPopup.value = true
  nextTick(() => {
    if (treeRef.value) {
      if (prop.multiple) {
        treeRef.value.updateTicked(prop.modelValue)
        showPopup.value = false
      } else treeRef.value.updateSelected(prop.modelValue)
    }
    formatFormInfo()
  })
  selected.value = prop.modelValue
}
watch(toRef(prop, 'modelValue'), () => initData(), { immediate: true })
const popupBlur = () => {
  emits('update:modelValue', selected.value || '')
  if (prop.lazyRules === 'ondemand') return
  nextTick(() => {
    if (!selectTree.value) return
    selectTree.value.blur()
    isValid.value = selectTree.value.validate()
  })
}
const handleClear = () => {
  selected.value = ''
  updateModelValue('', selected.value)
  popupBlur()
}

const scrollHandle = () => {
  if (!showPopup.value || !selectTree.value) return
  const offset = selectTree.value.$el.getBoundingClientRect()
  const innerHeight = window.innerHeight
  if (offset.top > innerHeight || offset.bottom < 0) showPopup.value = false
}
const resizeHandle = () => (showPopup.value = false)
onMounted(() => {
  window.addEventListener('scroll', scrollHandle, true)
  window.addEventListener('resize', resizeHandle, false)
})
onBeforeUnmount(() => {
  window.removeEventListener('scroll', scrollHandle, true)
  window.removeEventListener('resize', resizeHandle, false)
})

</script>